#include "Brick.h"
#include <iostream>  //GH temp for debugging
//testing SVN 1


Brick::Brick (char *Title, int ScreenWidth, int ScreenHeight, int ScreenBpp)
{
    if (ScreenHeight == sf::VideoMode::GetDesktopMode().Height && ScreenWidth == sf::VideoMode::GetDesktopMode().Width){
   	 MainWindow.Create(sf::VideoMode( ScreenWidth, ScreenHeight, ScreenBpp), Title, sf::Style::Fullscreen);
    }
    else{
   	 MainWindow.Create(sf::VideoMode( ScreenWidth, ScreenHeight, ScreenBpp), Title, sf::Style::Close);
    }

    MainWindow.SetFramerateLimit(0);
}

//defining the deconstructor
Brick::~Brick()
{
    //clean stuff up
}

//defining the initializer
bool Brick::Init(int BrickX, int BrickY, float ScaleX, float ScaleY)
{
    
    //initialize stuff
    //ShowWindow(GetConsoleWindow(), SW_HIDE); //hide the console window
    state = Menu;
    
    Brick_X = BrickX;   	 // Creates a copy of size variables for use in Brick Class
    Brick_Y = BrickY;

    Scale_X = ScaleX;   	 // Creates a copy of Scale Variables for the Brick Class
    Scale_Y = ScaleY;

    MoveX = Speed*ScaleX;    // Balances the speed of the ball
    MoveY = Speed*ScaleY;

    //sprite creation
    if (!Title2.LoadFromFile("Title.png") || !Image.LoadFromFile("Ball.png") || !Image2.LoadFromFile("Paddle.png") || !Image3.LoadFromFile("Bricks.png") || !Play.LoadFromFile("Play.png") || !Exit.LoadFromFile("Exit.png") || !image2.LoadFromFile("BG_Splash_Screen1.png") || !image3.LoadFromFile("BG_Splash_Screen2.png") || !image4.LoadFromFile("splash_menu.png") || !image5.LoadFromFile("NewGame.png") || !image6.LoadFromFile("Exit.png") || !image7.LoadFromFile("upperGameBar.png") || !image8.LoadFromFile("background.png") || !image9.LoadFromFile("gameover.png") || !image10.LoadFromFile("player_score.png") || !gamefont.LoadFromFile("Army.ttf") || !sound1.LoadFromFile("zap1.wav") || !sound2.LoadFromFile("zap2.wav") || !sound3.LoadFromFile("bounce.wav"))    //Testing whether images load or not
    {
   	 printf("\n\nCould not load an image or text");
   	 system("pause");
   	 return false;   	 // tells the program that it could not initialize correctly
    }
    BallSprite.SetImage(Image);
    BallSprite.SetCenter(BallSprite.GetSize().x/2, BallSprite.GetSize().y/2);
    BallSprite.SetScale(0.5*ScaleX, 0.5*ScaleX);    //Both Scales are X here to keep a round ball in odd shaped resolutions
    BallSprite.SetX(BrickX/2);    //sets it to the middle of the X axis screen after it has spawned
    BallSprite.SetY(BrickY/2);    //same for Y axis
    
    PaddleSprite.SetImage(Image2);
    PaddleSprite.SetCenter(PaddleSprite.GetSize().x/2, PaddleSprite.GetSize().y/2);
    PaddleSprite.SetScale(ScaleX, ScaleY);
    PaddleSprite.SetX(BrickX/2);    //sets it to the middle of the X axis screen after it has spawned
    PaddleSprite.SetY(BrickY - (50*ScaleY));    //same for Y axis

    PlaySprite.SetImage(Play);
    PlaySprite.SetCenter(PlaySprite.GetSize().x/2, PlaySprite.GetSize().y/2);
    PlaySprite.SetScale(ScaleX, ScaleY);
    PlaySprite.SetX(BrickX/2);
    PlaySprite.SetY(BrickY/1.4);

    ExitSprite.SetImage(Exit);
    ExitSprite.SetCenter(ExitSprite.GetSize().x/2, ExitSprite.GetSize().y/2);
    ExitSprite.SetScale(ScaleX, ScaleY);
    ExitSprite.SetX(BrickX/2);
    ExitSprite.SetY(BrickY/1.25);

    Title1.SetImage(Title2);
    Title1.SetCenter(Title1.GetSize().x/2, Title1.GetSize().y/2);
    Title1.SetScale(ScaleX, ScaleY);
    Title1.SetX(BrickX/2);
    Title1.SetY(BrickY/3);
    
    //bricks creation
    for(int i = 0; i < Row; i++)
    {
   	 for (int j = 0; j < Column; j++)
   	 {
   		 BrickSprite[i][j].SetImage(Image3);
   		 BrickSprite[i][j].SetCenter(BrickSprite[i][j].GetSize().x/2, BrickSprite[i][j].GetSize().y/2);    //sets the centre for the image
		 BrickSprite[i][j].SetScale(0.3*ScaleX, 0.3*ScaleY);
		 //GH start --ok position is not being set here.
		 //if (i > 0 && j > 0)
			//BrickSprite[i][j].SetPosition((i * 36),(j * 18)); //give the positions of the bricks here
			//BrickSprite[i][j].SetPosition((100),(100)); //testing
		 //GH end
   	 }
    }
	//GH Start
	//GH Start

	ScoreBoard.SetImage(image7);
	ScoreBoard.SetPosition(20,10);
	
	gameTimeClock.Reset();
	collisionClock.Reset(); //collision temp
	paddleClock.Reset(); //paddle clock checking for double hit
	ballClock.Reset();
	menuY = 0;
	playerScore = 0;
	//load images
	
	splash1.SetImage(image2);
	splash2.SetImage(image3);
	menubg.SetImage(image4);

	newGame.SetImage(image5);
	newGame.SetPosition(320,300);
	newGame.SetCenter(newGame.GetSize().x/2, newGame.GetSize().y/2); //changes the center of the image

	exitGame.SetImage(image6);
	exitGame.SetPosition(320,370);
	exitGame.SetCenter(exitGame.GetSize().x/2, exitGame.GetSize().y/2); //changes the cetner of the image
	
	gameBackground.SetImage(image8);
	gameOverBackground.SetImage(image9);
	highScoreBackground.SetImage(image10);

	timerString.SetFont(gamefont);
	timerString.SetPosition(140,16);

	bannerString.SetFont(gamefont);
	bannerString.SetPosition(26,16);
	bannerString.SetText("Time::             Score::               Lives::");
	
	
	livesString.SetFont(gamefont);
	livesString.SetPosition(570,16);

	scoreString.SetFont(gamefont);
	scoreString.SetPosition(360,16);


	zap1.SetBuffer(sound1); //load the buffer sound1 as the sound instance
	zap2.SetBuffer(sound2);
	bounce.SetBuffer(sound3);

	//GH End
    return true;

}

//defining update
void Brick::Update()
{
    ElapsedTime = Clock.GetElapsedTime();    //used for a constant speed across frame rates
    Clock.Reset();
    FPS = 1.f / ElapsedTime;


    //the switch statement and cases
    switch(state)
    {
   	 case Menu:
   		 
   		 Title1.SetImage(Title2);
   		 break;

   	 case Game:
   		 
   		 BallSprite.Move(MoveX * ElapsedTime, MoveY * ElapsedTime);


   		 if(BallSprite.GetPosition().y + BallSprite.GetSize().y/2 > Brick_Y - PaddleSprite.GetSize().y - 60)
   		 {
   			 Brick::Collider();
   		 }
   		 if(BallSprite.GetPosition().y - BallSprite.GetSize().y/2 < (30 + BrickSprite[0][0].GetSize().y) *Column + 25)
   		 {
   			 Brick::ColliderBrick();
   		 }


   		 //Wall collision
   		 //Left and Right
   		 if(BallSprite.GetPosition().x + BallSprite.GetSize().x/2 > Brick_X || BallSprite.GetPosition().x - BallSprite.GetSize().x/2 < 0)
   		 {
   			 bounce.Play();
			 MoveX *= -1;
   		 }
   		 //Top
   		 if(BallSprite.GetPosition().y - BallSprite.GetSize().y/2 < 0)
   		 {
   			 bounce.Play();
			 MoveY *= -1;
   		 }
   		 //Bottom
   		 if(BallSprite.GetPosition().y + BallSprite.GetSize().y/2 > Brick_Y)
   		 {
			
			BallSprite.SetPosition(Brick_X/2, Brick_Y/2);   	 //resets the ball to the middle
   			//PaddleSprite.SetPosition(Brick_X/2, PaddleSprite.GetPosition().y);    //resets the paddle to the middle //taken out due to it being impossible to get the paddle to the ball in time when both reset - would be an endless loop of losing the ball every time it spawns.
			 
			 if (lives == 1){
				state = gameover;
				menuClock.Reset();
			 }
			 else {
				 lives = lives - 1; //take away a life.
			 }

   		 }
   		 //GH Start - gameTimeClock
		 


		 //GH end
		 
		 break;
	 case gameover:
		 //GH call the highscore function here??? temp
		 //after timer> then reset the menuClock, gameTimeClock, score, lives, and set game state to menu
		 		 if (menuClock.GetElapsedTime() > 5) {
					 //OR should i just Game.Init(BrickX, BrickY, ScaleX, ScaleY); NO. that would reload images etc
					 menuClock.Reset();
					 gameTimeClock.Reset();
					 collisionClock.Reset();
					 paddleClock.Reset();
					 //score = 0;
					 lives = 5;
					 menubg.SetPosition(0,0);
					 menuY = 0;
					 playerScore = 0;
					 state = Menu;
				 }

		 break;
    }
}

//define draw
void Brick::Draw()
{
    MainWindow.Clear();
    switch(state)
    {

   	 case Menu:    //draw the menu screen
   		 //MainWindow.Draw(PlaySprite);  //GH remove
   		 //MainWindow.Draw(ExitSprite);  //GH remove
   		 //MainWindow.Draw(Title1);  //GH remove
		 MainWindow.Clear(); //temp??
		 //GH Menu goes here.
		 if (menuClock.GetElapsedTime() > 1 && menuClock.GetElapsedTime() < 3)
			MainWindow.Draw(splash1);

		if (menuClock.GetElapsedTime() > 3 && menuClock.GetElapsedTime() < 5)
			MainWindow.Draw(splash2);

		if (menuClock.GetElapsedTime() > 5)
			MainWindow.Draw(menubg);
		
		//App.Draw(menubg);
		//debugging
		//std::cout<<Clock.GetElapsedTime()<<std::endl;

		if(menuClock.GetElapsedTime() > 7 && menuY >= -180)
		{
			menubg.SetPosition(0,menuY);
			//some debug
			std::cout<<"GH MENU MOVING UP"<<std::endl;
			std::cout<<menuClock.GetElapsedTime()<<std::endl;
			menuY = menuY - 2;
		}
		
		if (menuY <= -180)
		{
			MainWindow.Draw(newGame);
			MainWindow.Draw(exitGame);
		}



   		 break;

   	 case Game:    //draw game objects
   		 MainWindow.Clear(); //temp??
		 MainWindow.Draw(gameBackground); //GH draws the background
		 MainWindow.Draw(ScoreBoard); //GH Draw the scoreboard
		 //GH
		 gameTimeDisplay = gameTimeClock.GetElapsedTime();
		 MainWindow.Draw(bannerString); //text for the banner that says Time Score Lives titles.
		 
		 sprintf(str, "%d", gameTimeDisplay); //change the int to a string
		 timerString.SetText(str); //timer display
		 MainWindow.Draw(timerString);

		 sprintf(str, "%d", lives); //change the int to a string
		 livesString.SetText(str);
		 MainWindow.Draw(livesString);

		 sprintf(str, "%d", playerScore);
		 scoreString.SetText(str);
		 MainWindow.Draw(scoreString);
		 
		 //GH end
		 MainWindow.Draw(BallSprite);    //draws the ball
   		 MainWindow.Draw(PaddleSprite);    //draws the paddle
		 

		 


   		 for(int i = 0; i < Row; i++)
   		 {    // drawing the bricks
   			 for (int j = 0; j < Column; j++)
   			 {
   				 if(BrickSprite[i][j].GetPosition().x > 0 && BrickSprite[i][j].GetPosition().y > 0){    //only draws the bricks that are on the screen
   					 MainWindow.Draw(BrickSprite[i][j]);
   				 }
   		 
   			 }
   		 }
   		 break;
	 case gameover:
		 MainWindow.Clear(); //temp??
		if (menuClock.GetElapsedTime() > 1 && menuClock.GetElapsedTime() < 3) //GH after 1 second draw the game over screen
			MainWindow.Draw(gameOverBackground);

		if (menuClock.GetElapsedTime() > 3) //after 3 seconds draw the high score screen.
			//MainWindow.Draw(highScoreBackground);
			MainWindow.Draw(gameOverBackground);

		 break;
    }
    MainWindow.Display();    // displays what has been drawn
}

//define the handle events
void Brick::HandleEvents()
{
    const sf::Input& Input = MainWindow.GetInput();
    

    if(Event.Type == sf::Event::Closed)
    {
   	 MainWindow.Close();
    }

    if((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
    {
   	 MainWindow.Close();
    }



    switch(state)
    {   	 //second switch statement for controls

   	 case Menu:

   		 //starting the game    if play is clicked
   		 if(Event.Type == sf::Event::MouseButtonPressed)
   		 {
   			 if (newGame.GetPosition().x + newGame.GetSize().x/2 > MainWindow.GetInput().GetMouseX() && newGame.GetPosition().x - newGame.GetSize().x/2 < MainWindow.GetInput().GetMouseX() && newGame.GetPosition().y - newGame.GetSize().y/2 < MainWindow.GetInput().GetMouseY() && newGame.GetPosition().y + newGame.GetSize().y/2 > MainWindow.GetInput().GetMouseY())
   			 {
   				 state = Game;
				 gameTimeClock.Reset(); //set the game timer counter.
				 lives = 5; //set the lives for the player.

   				 //brick positioner
   				 for(int i = 0; i < Row; i++)
   				 {
   					 for (int j = 0; j < Column; j++)
   					 {
   						 //BrickSprite[i][j].SetX((25*Scale_X + BrickSprite[i][j].GetSize().x) *(i+1));    //added to reset the position of the bricks
   						 //BrickSprite[i][j].SetY((30*Scale_Y + BrickSprite[i][j].GetSize().y) *(j+1));
						 //GH
						 BrickSprite[i][j].SetPosition(((i * 36)+64),((j * 18))+100); //give the positions of the bricks here
						 //GH
   					 }
   				 }


   			 }
   			 else if(exitGame.GetPosition().x + exitGame.GetSize().x/2 > MainWindow.GetInput().GetMouseX() && exitGame.GetPosition().x - exitGame.GetSize().x/2 < MainWindow.GetInput().GetMouseX() && exitGame.GetPosition().y - exitGame.GetSize().y/2 < MainWindow.GetInput().GetMouseY() && exitGame.GetPosition().y + exitGame.GetSize().y/2 > MainWindow.GetInput().GetMouseY())
   			 {
   				 MainWindow.Close();
   			 }
   		 }
   		 break;

   	 case Game:

   		 if((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Left))
   		 {
   			 PaddleSprite.Move((-40*(Speed)*Scale_X)*ElapsedTime,0);
   			 if(PaddleSprite.GetPosition().x - PaddleSprite.GetSize().x/2 < 0)
   			 {
   				 PaddleSprite.Move((40*(Speed)*Scale_X)*ElapsedTime, 0);
   			 }
   		 }
   		 if((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Right))
   		 {
   			 PaddleSprite.Move((4*(Speed*10)*Scale_X)*ElapsedTime,0);
   			 if(PaddleSprite.GetPosition().x + PaddleSprite.GetSize().x/2 > Brick_X)
   			 {
   				 PaddleSprite.Move((-4*(Speed*10)*Scale_X)*ElapsedTime, 0);   									 
   			 }
   		 }   	 
   		 break;
    }
}

//define run
void Brick::Run()
{
    while(MainWindow.IsOpened())
    {
   	 while(MainWindow.GetEvent(Event)) //GH while there is an event to get? ie it returns true/false?
   	 {
   		 HandleEvents();
   	 }
   	 Update();
   	 Draw();
    }
}

//collision between ball and paddle
void Brick::Collider()
{
    if(BallSprite.GetPosition().x - BallSprite.GetSize().x/2 - PaddleSprite.GetSize().x/2 < PaddleSprite.GetPosition().x && BallSprite.GetPosition().x + BallSprite.GetSize().x/2 + PaddleSprite.GetSize().x/2 > PaddleSprite.GetPosition().x && BallSprite.GetPosition().y - BallSprite.GetSize().y/2 - PaddleSprite.GetSize().y/2 < PaddleSprite.GetPosition().y && BallSprite.GetPosition().y + BallSprite.GetSize().y/2 + PaddleSprite.GetSize().y/2 > PaddleSprite.GetPosition().y)
    {
   		
		if (paddleClock.GetElapsedTime() > 1)
		{
			zap2.Play();
			MoveY *= -1;    // causes ball to reverse direction
			paddleClock.Reset();
		}


    }
}

//collision with the bricks
void Brick::ColliderBrick()
{
    for(int i = 0; i < Row; i++)
    {    // drawing the bricks
   	 for (int j = 0; j < Column; j++)
   	 {
		 //collision
   		 if(BallSprite.GetPosition().x - BallSprite.GetSize().x/2 - BrickSprite[i][j].GetSize().x/2 < BrickSprite[i][j].GetPosition().x && BallSprite.GetPosition().x + BallSprite.GetSize().x/2 + BrickSprite[i][j].GetSize().x/2 > BrickSprite[i][j].GetPosition().x && BallSprite.GetPosition().y - BallSprite.GetSize().y/2 - BrickSprite[i][j].GetSize().y/2 < BrickSprite[i][j].GetPosition().y && BallSprite.GetPosition().y + BallSprite.GetSize().y/2 + BrickSprite[i][j].GetSize().y/2 > BrickSprite[i][j].GetPosition().y)
   		 {
   			 
			 if (collisionClock.GetElapsedTime() > 0.1f) //if clock is greater than 100ms from the last collison
			 {
				 
				 
				 MoveY *= -1;    //causes the ball to reverse its direction

				 zap1.Play();
			
   				 BrickSprite[i][j].SetPosition(-500, -500);	//delete method (or rather, replacement method)
																//TEMP this needs to change for the win case.
				 playerScore = playerScore + 10;
				 collisionClock.Reset();
				 
			 }


   		 }

		 

   	 }
    }
}